import {Util} from "../utils/Util";
import {DataRouter} from "../frame/dataSource/DataRouter";
import {TimeControllerOpt} from "../controller/model/ControllerOpt";
import {TimeController} from "../controller/TimeController";
import {TriggerUtil} from "../utils/TriggerUtil";
import {
    AttributeEnum,
    AutocastDataData,
    BossAICondition,
    BossAIType,
    BossChoose,
    HurtType,
    PointEffectsType
} from "../frame/dataSource/DataModel";
import {AbilityController} from "../controller/AbilityController";
import {DataRouterUtil} from "../utils/router/DataRouterUtil";
import {UnitModel} from "../frame/apiModel/adapterModel/model3/UnitModel";
import {LocModel} from "../frame/apiModel/base/LocModel";
import {PlayerFactory} from "../frame/PlayerFactory";
import {ModelFactory} from "../frame/apiModel/adapterModel/model5/ModelFactory";
import {Logger} from "../frame/apiModel/config/Logger";
import {EffectModel} from "../frame/apiModel/adapterModel/model2/EffectModel";
import UnitUtil from "../utils/UnitUtil";
import {CodeUtil} from "../frame/codeAdapter/CodeUtil";
import {SpecialEffectType} from "../type/Type";

export function initBossAITrigger() {
    const autocastDatas = DataRouter.getAutocastDatas();
    for (let i = 0; i < autocastDatas.length; i++) {
        const autocastData = autocastDatas[i];
        const condition = autocastData.condition;
        switch (condition) {
            case BossAICondition.attackedNum: {
                const callback = function (attacker: UnitModel, attacked: UnitModel) {
                    const activeUnit = attacked;
                    const targetUnit = attacker;
                    const strId = activeUnit.strId;
                    if (autocastData.monster_id === strId) {
                        const spellLoc = targetUnit.loc;
                        const aiId = autocastData.id;
                        const num = autocastData.num;
                        const bCheck = AbilityController.getInstance().checkFrequency(activeUnit, aiId, num);
                        if (bCheck) {
                            useBossAI(activeUnit, targetUnit, autocastData, spellLoc);
                        }
                    }
                }
                UnitUtil.attackCallBack.push(callback);
                break;
            }
            case BossAICondition.attackNum: {
                const callback = function (attacker: UnitModel, attacked: UnitModel) {
                    const activeUnit = attacker;
                    const targetUnit = attacked;
                    const strId = activeUnit.strId;
                    if (autocastData.monster_id === strId) {
                        const spellLoc = targetUnit.loc;
                        const aiId = autocastData.id;
                        const num = autocastData.num;
                        const bCheck = AbilityController.getInstance().checkFrequency(activeUnit, aiId, num);
                        if (bCheck) {
                            useBossAI(activeUnit, targetUnit, autocastData, spellLoc);
                        }
                    }
                }
                UnitUtil.attackCallBack.push(callback);
                break;
            }
            case BossAICondition.life_percentage: {
                const callback = function (attacker: UnitModel, attacked: UnitModel) {
                    const activeUnit = attacked;
                    const targetUnit = attacker;
                    const strId = activeUnit.strId;
                    if (autocastData.monster_id === strId) {
                        const needPercentage = autocastData.num;
                        const lifeCurrent = Util.getTargetAttributeEnumByNotHero(targetUnit, AttributeEnum.life, true)
                        const lifeMax = Util.getTargetAttributeEnumByNotHero(targetUnit, AttributeEnum.maxLife, true)
                        const percentageCurrent = lifeCurrent / lifeMax;
                        const percentageNum = percentageCurrent * 100;
                        if (percentageNum <= needPercentage) {
                            const spellLoc = targetUnit.loc;
                            useBossAI(activeUnit, targetUnit, autocastData, spellLoc);
                        }
                    }
                }
                UnitUtil.attackCallBack.push(callback);
                break;
            }
            case BossAICondition.life: {
                const callback = function (attacker: UnitModel, attacked: UnitModel) {
                    const activeUnit = attacked;
                    const targetUnit = attacker;
                    const strId = activeUnit.strId;
                    if (autocastData.monster_id === strId) {
                        const needPercentage = autocastData.num;
                        const lifeCurrent = Util.getTargetAttributeEnumByNotHero(targetUnit, AttributeEnum.life, true)
                        if (lifeCurrent <= needPercentage) {
                            const spellLoc = targetUnit.loc;
                            useBossAI(activeUnit, targetUnit, autocastData, spellLoc);
                        }
                    }
                }
                UnitUtil.attackCallBack.push(callback);
                break;
            }
        }
    }
}

function getTargetGroup(activeUnit: UnitModel, targetUnit: UnitModel, unitLoc: LocModel, spellLoc: LocModel, bossAIData: AutocastDataData): UnitModel[] {
    const targetUnitArr: UnitModel[] = [];
    const choose = bossAIData.choose;
    const range = bossAIData.area;
    const maxUnitNum = bossAIData.max_unit;
    const activePlayer = PlayerFactory.getInstance().getUnitOwner(activeUnit);
    const activeIsPlaying = activePlayer.isNotEndPlaying();
    let filter: (unit: UnitModel) => boolean;
    filter = (unit: UnitModel): boolean => {
        const tempPlayer = PlayerFactory.getInstance().getUnitOwner(unit);
        const isEnemy = !tempPlayer.isPlayerAlly(activePlayer);
        const isAlive = DataRouterUtil.checkUnitUseAttr(unit);

        let playerCheck = true;
        const isPlayer = tempPlayer.isNotEndPlaying();
        if (!activeIsPlaying) {
            if (isPlayer) {
            } else {
                playerCheck = false;
            }
        }
        return isEnemy && isAlive && playerCheck;
    }
    switch (choose) {
        case BossChoose.all: {
            const tempTargetArr = [];
            ModelFactory.getInstance().mapUnitInRange(unitLoc, range,
                (unit) => {
                    if (filter(unit)) {
                        tempTargetArr.push(unit);
                    }
                }
            )
            if (!CodeUtil.isNullOrZero(maxUnitNum) && tempTargetArr.length > maxUnitNum) {
                for (let i = 0; i < maxUnitNum; i ++) {
                    const currentLen = tempTargetArr.length;
                    const random = activePlayer.getRandomInt(0, currentLen);
                    const retArr = tempTargetArr.splice(random, 1);
                    targetUnitArr.push(...retArr);
                }
            } else {
                targetUnitArr.push(...tempTargetArr);
            }
            break;
        }
        case BossChoose.closest: {
            let closestUnit;
            let closestDistance = 10000;
            ModelFactory.getInstance().mapUnitInRange(unitLoc, range,
                (unit) => {
                    if (filter(unit)) {
                    } else {
                        return;
                    }
                    const enmuUnit = unit;
                    const enmuLoc = enmuUnit.loc;
                    const distance = enmuLoc.getAbsDistance(unitLoc);
                    if (distance < closestDistance) {
                        closestDistance = distance;
                        closestUnit = enmuUnit;
                    }
                }
            )
            if (closestUnit) {
                targetUnitArr.push(closestUnit);
            }
            break;
        }
        case BossChoose.furthest: {
            let furthestUnit;
            let furthestDistance = 0;
            ModelFactory.getInstance().mapUnitInRange(unitLoc, range,
                (unit) => {
                    if (filter(unit)) {
                    } else {
                        return;
                    }
                    const enmuUnit = unit;
                    const enmuLoc = enmuUnit.loc;
                    const distance = enmuLoc.getAbsDistance(unitLoc);
                    if (distance > furthestDistance) {
                        furthestDistance = distance;
                        furthestUnit = enmuUnit;
                    }
                }
            )
            if (furthestUnit) {
                targetUnitArr.push(furthestUnit);
            }
            break;
        }
        case BossChoose.randomUnit: {
            const tempArr: UnitModel[] = [];
            ModelFactory.getInstance().mapUnitInRange(unitLoc, range,
                (unit) => {
                    if (filter(unit)) {
                    } else {
                        return;
                    }
                    tempArr.push(unit);
                }
            )
            let unit;
            const arrLen = tempArr.length;
            const random = activePlayer.getRandomInt(0, arrLen - 1);
            unit = tempArr[random];
            if (unit?.isValid()) {
                targetUnitArr.push(unit);
            }
            break;
        }
    }
    return targetUnitArr;
}

function useBossAI(activeUnit: UnitModel, targetUnit: UnitModel, bossAIData: AutocastDataData, spellLoc: LocModel) {
    Logger.toastSkill(`开始判断boss技能`)
    if (activeUnit?.isAliveInBattle() && targetUnit?.isAliveInBattle()) {
    } else {
        Logger.toastSkill(`单位已死亡，停止释放`)
        return;
    }
    const activePlayer = PlayerFactory.getInstance().getUnitOwner(activeUnit);
    const unitLoc = targetUnit.loc;
    const targetUnitArr = getTargetGroup(activeUnit, targetUnit, unitLoc, spellLoc, bossAIData);
    const pointEffect = bossAIData.point_effects;
    const probability = bossAIData.probability;
    let randomInt = activePlayer.getRandomInt(1, 100);
    const failure_tip = bossAIData.failure_tip;
    if (probability < randomInt) {
        if (failure_tip) {
            Logger.toastProduct(failure_tip)
        }
        return false;
    }

    const delay_time = bossAIData.delay;

    // 使用者特效
    if (!CodeUtil.isNullOrZero(delay_time)) {
        const self_effects = bossAIData.self_effects;
        const self_effects_point = bossAIData.self_effects_point;
        if (self_effects) {
            TimeController.addSpecialEffectByResourceIdFun(activeUnit, self_effects, delay_time, undefined, self_effects_point, SpecialEffectType.unit, 0, 0)
        }
    }

    const targetLocArr: LocModel[] = [];
    targetUnitArr.forEach((value, index, array) => {
        const enumUnit = value;
        const loc = enumUnit.loc;
        targetLocArr.push(loc);
        let targetEffect: EffectModel;
        let targetUnitEffect: EffectModel;
        if (!CodeUtil.isNullOrZero(delay_time)) {
            if (bossAIData.point_effects_type === PointEffectsType.line) {
                const activeLoc = activeUnit.loc;
                const angle = activeLoc.getAngle(loc);
                TimeController.addSpecialEffectByResourceIdFun(activeUnit, pointEffect, delay_time, activeLoc, undefined, SpecialEffectType.point, 0, angle)
            } else {
                TimeController.addSpecialEffectByResourceIdFun(activeUnit, pointEffect, delay_time, loc, undefined, SpecialEffectType.point, 0, 0)
            }
            // 目标单位特效
            const target_effects = bossAIData.target_effects;
            if (target_effects) {
                const target_effects_point = bossAIData.target_effects_point;
                TimeController.addSpecialEffectByResourceIdFun(enumUnit, target_effects, delay_time, loc, target_effects_point, SpecialEffectType.unit, 0, 0)
            }
        }
    })
    const abilityId = bossAIData.skill_id;
    const delayCallBack = function () {
        Logger.toastSkill(`boss开始释放技能`)
        if (activeUnit?.isAliveInBattle()) {
        } else {
            Logger.toastSkill(`单位已死亡，停止释放`)
            return;
        }
        const tip = bossAIData.tip;
        if (tip) {
            Logger.toastProduct(tip)
        }
        // const sound = bossAIData.sound_effect;
        // StartSoundForPlayerBJ(player, soundName);
        const type = bossAIData.type;
        if (type === BossAIType.vest) {
            const effectData = DataRouter.getEffectByEffectId(abilityId);
            if (effectData) {
                targetUnitArr.forEach((value, index, array) => {
                    if (DataRouterUtil.checkUnitUseAttr(value)) {
                    } else {
                        Logger.toastSkill(`单位已死亡，停止释放`)
                        return;
                    }
                    TriggerUtil.useAbilityEffect(activeUnit, value, effectData, targetLocArr[index], 1);
                })
            } else {
                Logger.toastError(`不能让单位 ${activeUnit.name} 释放一个不存在的技能效果 ${abilityId}`)
            }
        } else {
            TriggerUtil.activeUseAbility(activeUnit, abilityId, targetUnitArr, targetLocArr, '', HurtType.spell,0, false);
        }
    }
    if (!CodeUtil.isNullOrZero(delay_time)) {
        const timerOpt = new TimeControllerOpt(undefined, delayCallBack, 1);
        TimeController.getInstance().startTimer({time: delay_time, opt: timerOpt});
    } else {
        delayCallBack();
    }
}